<?php

namespace app\common\model;

use app\common\library\Auth;
use app\common\model\PostMan as PostmanModel;
use app\common\service\StockService;
use Symfony\Component\HttpFoundation\Session\Storage\Proxy\SessionHandlerProxy;
use think\Exception;
use think\Model;
use think\Db;
use app\common\library\Weixin;
use app\common\controller\Queue;


class ShipOrder extends Model
{

    

    

    // 表名
    protected $name = 'ship_order';
    
    // 自动写入时间戳字段
    protected $autoWriteTimestamp = 'int';

    // 定义时间戳字段名
    protected $createTime = 'create_time';
    protected $updateTime = 'update_time';
    protected $deleteTime = false;

    // 追加属性
    protected $append = [
        'sign_time_text',
	    'status_text'
    ];
	
	
	const STATUS_WAIT = 0;
	const STATUS_SUCCESS = 1;
	const STATUS_SHIPPING = 2;
	const STATUS_CLOST = 4;
	
	public static $statusList = [
		self::STATUS_SUCCESS => '已签收',
		self::STATUS_WAIT => '待签收',
		self::STATUS_SHIPPING => '待配送',
		self::STATUS_CLOST => '已关闭'
	];
	
	public function getStatusTextAttr($value, $data) {
		$value = $value ? : $data['status'];
		$list = self::$statusList;
		return $list[$value] ?? '';
	}



    public function getSignTimeTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['sign_time']) ? $data['sign_time'] : '');
        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
    }

    protected function setSignTimeAttr($value)
    {
        return $value === '' ? null : ($value && !is_numeric($value) ? strtotime($value) : $value);
    }
	
	
	public function send() {
		return $this->belongsTo('agentShop', 'send_agent_id', 'id', '', 'left')->setEagerlyType(0);
	}
	
	
	public function signagent() {
		return $this->belongsTo('agentShop', 'sign_agent_id', 'id', '', 'left')->setEagerlyType(0);
	}
	
	public function postman() {
		return $this->belongsTo('postMan', 'postman_id', 'id', '', 'left')->setEagerlyType(0);
	}
	
	/**
	 * 发货
	 * @param $area 区域
	 * @param $shippingName 快递名称
	 * @param $shippingNo 快递单号
	 * @param $numberList 发货商品及数量
	 * @param $signAgent 签收的代理
	 * @param string $sendAgent 发货的代理
	 * @param string $postmanId 配送员
	 * @param int $destoryNumber 核销的奖励数量
	 * @param boolean $isPostman 是否宝能发货
	 * @return bool|string
	 * @throws \think\exception\PDOException
	 */
	public function sendGoods($area, $shippingName, $shippingNo, $numberList, $signAgent, $sendAgent = '', $postmanId = '', $destoryNumber = 0, $isPostman = false) {
		$stockModel = new StockWarning();
		$this->startTrans();
		try {
			$sendAgentId =$sendAgent ? $sendAgent['id'] : '';
			//添加发货订单
			$orderId = $this->addOrder($area, $signAgent['id'], $shippingName, $shippingNo, $sendAgentId, $postmanId, $destoryNumber);
			if(!$orderId) {
				throw new Exception('添加发货订单出错');
			}
			$data = [];
			$taskList = [];
			
			//兼容旧接口处理
			if(is_string($numberList)) {
				$numberList = array_filter(explode(',', $numberList));
			}
			if($numberList) {
				
				foreach ($numberList as $key => $number) {
					//兼容旧接口处理
					if (is_numeric($key)) {
						$keys = explode('_', $number);
						$number = $keys[2];
					} else {
						$keys = explode('_', $key);
					}
					
					if ($number <= 0) {
						continue;
					}
					
					if (!isset($keys[0]) || !isset($keys[1])) {
						throw new Exception('参数错误');
					}
					
					$goodsId = $keys[0];
					$specId = $keys[1];
					
					//宝能发货要检测有没有导出记录
					if ($isPostman) {
						$remindRes = $this->checkRemind($goodsId, $specId, $signAgent['id'], $number);
						if (!$remindRes) {
							throw new Exception($this->getError());
						}
					}
					
					//发货数量加现在库存不能超过系统设计的数量
					$sendNumber = $stockModel->checkSendMaxNumer($goodsId, $specId, $signAgent['id'], $number,
						$signAgent['area'], $signAgent['role']);
					if (!$sendNumber) {
						throw new Exception($stockModel->getError());
					}
					
					//不是总部发货要减少库存
					if ($sendAgent) {
						$stockRes = StockService::changeStock($sendAgent['user_id'], $goodsId, $specId, $number);
						if ($stockRes !== true) {
							throw new Exception($stockRes);
						}
						$taskList[] = ['id' => $sendAgent['id'], 'goods_id' => $goodsId, 'spec_id' => $specId];
					} else {
						//总部发货要生成宝能发货记录
						$remindModel = new ShipRemind();
						$remindRes = $remindModel->addRow($signAgent['id'], $goodsId, $specId, $number);
						if (!$remindRes) {
							throw new Exception('添加宝能发货记录出错');
						}
					}
					
					$data[] = [
						'order_id' => $orderId,
						'goods_id' => $goodsId,
						'spec_id' => $specId,
						'number' => $number
					];
				}
			}
			if(!$data && $destoryNumber <= 0) {
				throw new Exception('请输入发货数量或核销奖励数量');
			}
			
			if($data) {
				$itemRes = Db::name('shipItem')
					->insertAll($data);
				if(!$itemRes) {
					throw new Exception('添加订单商品出错');
				}
			}
			
			//减少奖励数量
			if($destoryNumber > 0) {
				$destoryRes = $this->destoryGiftNumber($signAgent['user_id'], $destoryNumber, $signAgent['id'], $sendAgent);
				if(!$destoryRes) {
					throw new Exception('减少奖励数量出错');
				}
			}
			
			Message::add($signAgent['user_id'], '签收提醒', '你的上级已发货，请注意查收入库!');
			$this->commit();
			
			$this->sendSendTemplate($signAgent['user_id'], $signAgent['name']);
			
			//添加库存检测任务
			if($taskList) {
				foreach ($taskList as $item) {
					Queue::addTask('checkStock', $item);
				}
			}
			
			return true;
		} catch (Exception $e) {
			$this->rollback();
			$this->error = $e->getMessage();
			return false;
		}
	}
	
	/**
	 * 添加发货订单
	 * @param $area 区域
	 * @param $signAgentId 签收代理ID
	 * @param $shippingName 快递名称
	 * @param $shippingNo 快递单号
	 * @param $sendAgentId 发货代理ID
	 * @param $postmanId 配送号ID
	 * @param int $destoryNumber 核销奖励数量
	 * @return bool|string
	 */
    public  function addOrder($area, $signAgentId, $shippingName, $shippingNo, $sendAgentId, $postmanId, $destoryNumber = 0) {
    	
    	$status =$postmanId ? self::STATUS_SHIPPING : self::STATUS_WAIT;
    	if($postmanId) {
    		$userId = Auth::instance()->id;
    		$postman = PostmanModel::get($postmanId);
    		if($postman['user_id'] == $userId) {
    		    $status = self::STATUS_WAIT;
		    }
	    }
    	$res = $this->isUpdate(false)
		    ->save([
		    	'area' => $area,
		    	'no' => time().mt_rand(1000, 9999),
		    	'sign_agent_id' => $signAgentId,
			    'send_agent_id' => $sendAgentId,
			    'postman_id' => $postmanId,
			    'shipping_name' => $shippingName,
			    'shipping_no' => $shippingNo,
			    'send_code' => time().mt_rand(1000, 9999),
			    'sign_code' => time().mt_rand(1000, 9999),
			    'status' => $status,
			    'destory_number' => $destoryNumber
		    ]);
    	
    	if($res) {
    		return $this->getLastInsID();
	    }
    	
    	return false;
    }
	
	/**
	 * 核销下级核销的赠酒数量
	 * @param $userId 核销的用户ID
	 * @param $number 核销数量
	 * @param string $agentId 核销的用户代理ID
	 * @param string $shop 发货的代理
	 * @return bool
	 */
	public function destoryGiftNumber($userId, $number, $agentId= '', $shop = '') {
		$agent = Db::name('agentShop')->where(['user_id' => $userId])->find();
		if($agent['gift_number'] < $number) {
			$this->error = '当前下级剩余赠送数量为'.$agent['gift_number'];
			return false;
		}
		
		
		$userRes = Db::name('agentShop')
			->where(['id' => $agent['id']])
			->setDec('gift_number', $number);
		if(!$userRes) {
			$this->error = '减少赠送数量出错';
			return false;
		}
		
		$recordRes = RewardRecord::addRecord($userId, -$number, '上级已发货核销');
		if(!$recordRes) {
			$this->error = '添加发货核销记录出错';
			return false;
		}
		
		$messageRes = Message::add($userId, '奖励瓶数已发货', '你的奖励瓶数已发放，数量'.$number.'瓶，请注意查收，如有异议，请与上级或客服联系');
		
		
		if($shop && $shop['role'] == \app\admin\model\User::LEVEL_THEATER) {
			$theaterNumberRes = Db::name('agentShop')
				->where(['user_id' => $shop['user_id']])
				->setInc('gift_number', $number);
			if(!$theaterNumberRes) {
				$this->error = '添加战区赠酒数量出错';
				return false;
			}
			$recordRes = RewardRecord::addRecord($shop['user_id'], $number, '核销下级添加', $agentId);
			if(!$recordRes) {
				$this->error = '添加战区奖励记录出错';
				return false;
			}
		}
		
		
		return true;
	}
	
	/**
	 * 核销奖励数量
	 * @param $userId 核销的用户ID
	 * @param $number 核销数量
	 * @param string $agentId 核销的用户代理ID
	 * @param string $shop 发货的代理
	 * @return bool
	 */
    public function destoryNumber($userId, $number, $agentId= '', $shop = '') {
	    $user = Db::name('user')->find($userId);
	    if($user['reward_number'] < $number) {
		    $this->error = '当前下级剩余奖励数量为'.$user['reward_number'];
		    return false;
	    }
	
	
	    $userRes = Db::name('user')
		    ->where(['id' => $userId])
		    ->setDec('reward_number', $number);
	    if(!$userRes) {
	    	$this->error = '减少奖励数量出错';
	    	return false;
	    }
	
	    $recordRes = RewardRecord::addRecord($userId, -$number, '已发货奖励');
	    if(!$recordRes) {
		    $this->error = '添加奖励记录出错';
		    return false;
	    }
	    
	    $messageRes = Message::add($userId, '奖励瓶数已发货', '你的奖励瓶数已发放，数量'.$number.'瓶，请注意查收，如有异议，请与上级或客服联系');
	    
	
	    if($shop && $shop['role'] == \app\admin\model\User::LEVEL_THEATER) {
		    $theaterNumberRes = Db::name('user')
			    ->where(['id' => $shop['user_id']])
			    ->setInc('reward_number', $number);
		    if(!$theaterNumberRes) {
			    $this->error = '添加战区奖励数量出错';
			    return false;
		    }
		    $recordRes = RewardRecord::addRecord($shop['user_id'], $number, '核销下级添加', $agentId);
		    if(!$recordRes) {
			    $this->error = '添加战区奖励记录出错';
			    return false;
		    }
	    }
	    
	    
	    return true;
    }
    
    /**
     * 发送模板消息
	 * @param $userId
	 * @param $agentName
	 */
    public function sendSendTemplate($userId, $agentName) {
	    $formIdRow = Db::name('formId')->alias('f')
		    ->join('user u', 'f.user_id = u.id', 'left')
		    ->where(['f.user_id' => $userId, 'number' => 0, 'create_time' => ['egt', strtotime('-7 days')]])
		    ->field('f.id, u.smallapp_openid, f.form_id')
		    ->find();
	
	    if($formIdRow) {
		    $config= config('weixin');
		    $templateId = $config['smallapp']['message_template']['send_tips'];
		    $data = [
			    'keyword1' => ['value' => $agentName],
			    'keyword2' => ['value' => '你的上级已发货，请注意查收入库!'],
		    ];
		    $obj = new Weixin($config['smallapp']['app_id']);
		    $page = 'pages/index/index';
		    $res = $obj->sendTemplate($formIdRow['smallapp_openid'], $templateId, $formIdRow['form_id'],$data, $page);
		    if($res === true) {
			    Db::name('formId')->where(['id' => $formIdRow['id']])->setInc('number');
		    }
	    }
    }
	
	
	/**
	 * 获取发货订单
	 * @param $page 页数
	 * @param string $signAgentId 收货代理ID
	 * @param string $sendAgendId 发货代理ID
	 * @param string $postmanIds 配送员ID
	 * @param string $status 状态
	 * @return array
	 * @throws Exception
	 * @throws \think\db\exception\DataNotFoundException
	 * @throws \think\db\exception\ModelNotFoundException
	 * @throws \think\exception\DbException
	 */
    public function getOrder($page, $signAgentId = '', $sendAgendId = '', $postmanIds = '', $status= '') {
    	$where['o.id'] = ['gt', 0];
    	
    	strlen($signAgentId) > 0 && $where['o.sign_agent_id'] = $signAgentId;
	    $sendAgendId && $where['o.send_agent_id'] = $sendAgendId;
	    $postmanIds && $where['o.postman_id'] = ['in', $postmanIds];
	
	    if(strlen($status) > 0) {
		    $where['o.status'] = $status;
	    }
	    
    	
    	$total = Db::name('shipOrder')->alias('o')
		    ->where($where)
		    ->count();
    	
    	
    	$orders = Db::name('shipOrder')->alias('o')
		    ->join('agentShop sa', 'o.sign_agent_id = sa.id', 'left')
		    ->join('agentShop ss', 'o.send_agent_id = ss.id', 'left')
		    ->join('postMan p', 'o.postman_id = p.id', 'left')
		    ->order(['o.create_time' => 'desc'])
		    ->where($where)
		    ->page($page)
		    ->field('o.id, o.no, o.destory_number, o.postman_id, o.area, o.status, o.sign_code, o.send_code, from_unixtime(o.create_time, \'%Y/%m/%d\') as date, sa.name as sign_name, ss.name as send_name')
		    ->select();
    	
    	if($orders) {
		    $statusList = ShipOrder::$statusList;
    		foreach ($orders as &$order) {
    	        $order['status_text'] = $statusList[$order['status']];
    	        $order['goods'] = Db::name('shipItem')->alias('i')
		            ->join('goods g', 'i.goods_id = g.id', 'left')
		            ->join('goodsSpec s', 'i.spec_id = s.id', 'left')
		            ->field('i.id, i.number, g.name, g.image, s.name as spec_name')
		            ->where(['i.order_id' => $order['id']])
		            ->select();
		    }
	    }
    	
    	return [
    		'total' => $total,
		    'list' => $orders,
		    'page' => $page
	    ];
    }
	
	
	/**
	 * 签收入库
	 * @param $no 批次号
	 * @param $agentId 代理ID
	 * @param $userId 用户ID
	 * @return bool
	 * @throws \think\exception\PDOException
	 */
	public function sign($no, $agentId, $userId) {
		$this->startTrans();
		try {
			
			$where = ['sign_agent_id' => $agentId, 'no' => $no, 'status' => self::STATUS_WAIT];
			$order = Db::name('shipOrder')
				->where($where)
				->find();
			
			if(!$order) {
				throw new Exception('要签收的订单不存在');
			}
			
			//更改订单状态
			$res = $this->save(['status' => self::STATUS_SUCCESS, 'sign_time' => time()], ['id' => $order['id']]);
			if(!$res) {
				throw new Exception('更改签收状态出错');
			}
			
			$isPostman = false;
			//检测是不是宝能发的货，如果是，要更改发货提醒记录的状态
			if($order['postman_id']) {
				$row = Db::name('postMan')->alias('p')
					->join('agentShop a', 'p.agent_id = a.id', 'left')
					->where(['p.id' => $order['postman_id']])
					->field('p.id, p.name, p.mobile, a.role, a.area')
					->find();
				if($row && $row['area'] == \app\admin\model\User::AREA_SZ && $row['role'] == \app\admin\model\User::LEVEL_THEATER) {
					$isPostman = true;
				}
			}
			
			$goodsList = Db::name('shipItem')
				->where(['order_id' => $order['id']])
				->select();
			
			$stockModel = new AgentStock();
			$recModel = new AgentStockRecord();
			foreach ($goodsList as $item) {
				//添加库存
				$numRes = $stockModel->add($userId, $agentId, $item['goods_id'], $item['spec_id'], $item['number']);
				if(!$numRes) {
					throw new Exception('添加库存出错');
				}
				
				//记录库存记录
				$recRes = $recModel->addRecord($userId, $item['goods_id'], $item['spec_id'], $recModel::TYPE_IN, $item['number'], '签收入库');
				if(!$recRes) {
					throw new Exception('添加库存记录出错');
				}
				
				//宝能发货，更改提醒记录状态为已完成
				if($isPostman) {
					$remainRes = Db::name('shipRemind')->where([
						'goods_id' => $item['goods_id'], 'spec_id' => $item['spec_id'], 'agent_id' => $agentId, 'status' => ShipRemind::STATUS_WAIT_SING
					])->update(['status' => ShipRemind::STATUS_DONE, 'update_time' => time()]);
					if(!$remainRes) {
						throw new Exception('更改发货提醒记录状态出错');
					}
				}
			}
			
			
			$this->commit();
			return true;
		} catch (Exception $e) {
			$this->rollback();
			$this->error = $e->getMessage();
			return false;
		}
	}
	
	
	/**
	 * 宝能发货要检测记录和数量，然后更改状态
	 * @param $goodsId
	 * @param $specId
	 * @param $agentId
	 * @param $number
	 * @return bool|int|string
	 * @throws Exception
	 * @throws \think\db\exception\DataNotFoundException
	 * @throws \think\db\exception\ModelNotFoundException
	 * @throws \think\exception\DbException
	 * @throws \think\exception\PDOException
	 */
	public function checkRemind($goodsId, $specId, $agentId, $number) {
		$goods = Db::name('goods')->alias('g')
			->join('goods_spec s', 'g.id = s.goods_id and s.id = '.$specId, 'left')
			->where(['g.id' => $goodsId])
			->field('g.name, s.name as spec_name')
			->find();
		$goodsName = $goods['spec_name'] ? :''.$goods['name'];
		
		$remainRow = Db::name('shipRemind')->where([
			'goods_id' => $goodsId,
			'spec_id' => $specId,
			'agent_id' => $agentId,
			'status' => ShipRemind::STATUS_WAIT_SEND
		])->find();
		
		if(!$remainRow) {
			$this->error = $goodsName.'没有待发货记录';
			return false;
		}
		
		if($number != $remainRow['number']) {
			$this->error = $goodsName.'待发货数量为'.$remainRow['number'];
			return false;
		}
		
		$sendRes = Db::name('shipRemind')->where(['id' => $remainRow['id']])
			->update([
				'update_time' => time(),
				'status' => ShipRemind::STATUS_WAIT_SING
			]);
		
		if(!$sendRes) {
			$this->error = '更改待发货记录状态出错';
			return false;
		}
		return $sendRes;
	}
}
